ExternalDNSでPrivate Hosted ZoneとPublic Hosted Zoneにレコードを出し分ける
こんにちは、かたいなかです。
ExternalDNSを使用するとKubernetesのYAML内でドメイン名を指定するだけで、Route53のHosted Zoneにレコードが登録でき便利です。
実際にExternalDNSを使用していたのですが、外部向けELBのエンドポイントはPublic Hosted Zoneに、内部向けELBのエンドポイントはPriate Hosted Zoneにレコードを登録させたい状況が発生しました。
その際、ExternalDNSの--annotation-filter
というオプションを指定して適切なHosted Zoneへレコードを登録させるようにしたので、その際の内容を備忘録として記事にまとめます。
環境
- Kubernetes バージョン 1.10
- EKS プラットフォームバージョン eks.2
- kube2iam 0.10.4
- ワーカーノードとなるEC2インスタンスのロールが汚れるのが嫌なので先に導入しています。 EKSへの導入手順はこちらの記事を参考にしました。
- ExternalDNS 0.5.8
今回やりたいこと
図のように、LoadBalancer Serviceが作成するELBのエンドポイントに対して、
- 内部向けELBはエンドポイントをPrivate Hosted ZoneにALIASレコードとして登録します。
- 外部向けのELBはエンドポイントをPublic Hostex ZoneにALIASレコードとして登録します。
Hosted Zoneの作成
Record Setの登録先となるHosted Zoneを先に作成しておきます。下のようなコマンドを使用して作成しました。
$ aws route53 create-hosted-zone \ --name <ドメイン名> \ --caller-reference <任意の値> # public hosted zoneの作成 $ aws route53 create-hosted-zone \ --name <ドメイン名> \ --vpc 'VPCRegion=<region>,VPCId=<vpc-id>' \ --caller-reference <任意の値> # private hosted zoneの作成
ExternalDNSのデプロイ
次にExternalDNSをデプロイしていきます。
基本的には、こちらのExternalDNSのドキュメントに沿って進めましたが、Hosted Zoneの振り分けおよびkube2iamを使用するため、2点変更を行いました。
- External DNS用IAMロールをkube2iamで使用できるようにするため、信頼関係のポリシーを少し変更しました。
- Deploymentについては、以下で紹介する設定のように
--annotation-filter
というオプションを使用してPublic用とPrivate用の2つを作成するようにしました。
変更した点に絞って設定内容を紹介します。
External DNS用IAMロールの作成
ExternalDNSに必要な権限を持ち、kube2iamでExternalDNSのPodに割り当てられるようにロールを作成していきます。
IAMロールには、こちらのExternalDNSのドキュメントに従い以下のようなポリシードキュメントで表されるような権限をもつIAM Policyをアタッチしました。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "route53:ChangeResourceRecordSets" ], "Resource": [ "arn:aws:route53:::hostedzone/*" ] }, { "Effect": "Allow", "Action": [ "route53:ListHostedZones", "route53:ListResourceRecordSets" ], "Resource": [ "*" ] } ] }
また、このロールをkube2iamでPodに割り当てることができるようにするため、Trust Policyはこちらの記事を参考に以下のようにしました。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" }, { "Effect": "Allow", "Principal": { "AWS": "<ワーカーノードインスタンスのロールARN>" }, "Action": "sts:AssumeRole" } ] }
Public Hosted Zoneに外部向けELBのRecord Setを登録させる設定
ExternalDNSのDeploymentの設定です。振り分けを行うため、2つ作成するDeploymentのうちのPublic Hosted Zone用の設定です。
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: external-dns-public spec: strategy: type: Recreate template: metadata: labels: app: external-dns-private annotations: iam.amazonaws.com/role: <先に作成しておいたExternalDNSに必要な権限を持ったIAMロール名 (not ARN)> spec: serviceAccountName: external-dns containers: - name: external-dns image: registry.opensource.zalan.do/teapot/external-dns:latest args: - --source=service - --source=ingress - --domain-filter=<Hosted Zoneのドメイン名> - --provider=aws - --policy=upsert-only - --aws-zone-type=public # Public Hosted Zoneに登録 - --registry=txt - --annotation-filter=service.beta.kubernetes.io/aws-load-balancer-internal=false # 外部向けELBのみ対象 - --txt-owner-id=my-identifier
Public Hosted Zone用のDeploymentではExternalDNSのオプションとして以下のものを指定しました。
--aws-zone-type=private
と指定し、Public Hosted Zoneに登録--annotation-filter=service.beta.kubernetes.io/aws-load-balancer-internal=false
と指定し、外部向けELBのみ対象- annotation-filterでこのように指定したため、外部向けELBを作成するLoadBalancer Serviceでは、
アノテーションで、
service.beta.kubernetes.io/aws-load-balancer-internal:"false"
と明示的に外部向けLBであることを指定する必要があります。 - 今回はLoadBalancer Serviceが対象のため、
service.beta.kubernetes.io/aws-load-balancer-internal
というアノテーションを指定していますが、Ingressの場合はkubernetes.io/ingress.class
というアノテーションを指定すると良いようです(参考)。
- annotation-filterでこのように指定したため、外部向けELBを作成するLoadBalancer Serviceでは、
アノテーションで、
また、Deploymentのannotationでiam.amazonaws.com/role: external-dns-iam-role
のように指定し、ExternalDNSに必要な権限を持ったIAMロールをPodに割り当てるようにしました。
Private Hosted Zoneに内部向けELBのRecord Setを登録させる設定
振り分けを行うため、2つ作成するDeploymentのうちのPrivate Hosted Zone用の設定です。
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: external-dns-private spec: strategy: type: Recreate template: metadata: labels: app: external-dns-private annotations: iam.amazonaws.com/role: <先に作成しておいたExternalDNSに必要な権限を持ったIAMロール名 (not ARN)> spec: serviceAccountName: external-dns containers: - name: external-dns image: registry.opensource.zalan.do/teapot/external-dns:latest args: - --source=service - --source=ingress - --domain-filter=<Hosted Zoneのドメイン名> - --provider=aws - --policy=upsert-only - --aws-zone-type=private # Private Bosted Zoneに登録 - --registry=txt - --annotation-filter=service.beta.kubernetes.io/aws-load-balancer-internal=true # 内部向けELBのみ対象 - --txt-owner-id=my-identifier
Private Hosted Zone用のDeploymentではExternalDNSのオプションとしてPublic Hosted Zone用のときと同様に以下のものを指定しました。
--aws-zone-type=private
と指定し、Private Hosted Zoneに登録--annotation-filter=service.beta.kubernetes.io/aws-load-balancer-internal=true
と指定し、内部向けELBのみ対象に
IAMロールに関してもPublic Hosted Zone用の設定と同様です。
ここまで紹介した変更点以外は、こちらのExternalDNSのドキュメントに載っている設定をそのまま使用します。
動作確認
ここまででExternalDNSの準備はできたので実際に外部向け/内部向けロードバランサーを作成し、動作確認してみましょう。
外部向けELBを作成するLoadBalancer Serviceを作成してみる
apiVersion: v1 kind: Service metadata: name: external-lb annotations: external-dns.alpha.kubernetes.io/hostname: external-app.katainaka.org service.beta.kubernetes.io/aws-load-balancer-internal: "false" spec: type: LoadBalancer selector: app: external-app ports: - protocol: TCP port: 80 targetPort: 8080
上のようなYAMLで外部向けELBを作成するServiceを作成すると、以下の画像のように指定したドメインのPublic Hosted Zoneに、Serviceから作成されたELBに結びついたALIASレコードが登録されました。
内部向けELBを作成するLoadBalancer Serviceを作成してみる
apiVersion: v1 kind: Service metadata: name: internal-lb annotations: external-dns.alpha.kubernetes.io/hostname: internal-app.katainaka.org service.beta.kubernetes.io/aws-load-balancer-internal: "true" spec: type: LoadBalancer selector: app: internal-app ports: - protocol: TCP port: 80 targetPort: 8080
上のようなYAMLで内部向けELBを作成するServiceを作成すると、以下の画像のように指定したドメインのPrivate Hosted Zoneに、Serviceから作成されたELBに結びついたALIASレコードが登録されました。
まとめ
ExternalDNSの--annotation-filter
というオプションを使用することで、アノテーションの値に基づいてどのHosted Zoneにレコードを登録するかを振り分けることができました。今回はLoadBalancer Serviceで試しましたがExternalDNSはIngressにも対応しているためIngressでも同様のことを行うことが可能です。